
#include "Engine.h"
#include "ComponentManager.h"

#include <iostream>
using namespace std;
#define SHOWFPS

#include "ShapeRectangle.h"
#include "ShapeCircle.h"

CEngine::CEngine(void):m_running(false), m_screen(0), m_screenWidth(0), m_screenHeight(0), m_screenDepth(0),
m_fps(0), m_fpsTicks(0), m_fpsCounter(0), m_lastTick(0){}

CEngine::~CEngine(void)
{
	SDL_Quit();
}

void CEngine::init(void)
{
	//initialise the console logger
	if(!CM.initLogger("LOG_Console"))
	{
		CM.close();
		exit(1);
	}

	if(!CM.initLogger("LOG_MsgBox"))
	{
		CM.close();
		exit(1);
	}

	//initialise SDL
	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)==0)
		CM.LOGCONSOLE().Log()<<"LOG : ENGINE : SDL initialised\n";
	else
	{
		CM.LOGCONSOLE().Log()<<"LOG : ENGINE : ERROR : SDL not initialised\n";
		CM.close();
		exit(1);
	}


		
	//initialise the visualisation component
	if(!CM.initVisualisationComponent("SDL_Visualisation"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the audio component
	if(!CM.initAudioComponent("SDL_Audio"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the user interface component
	string uiComponentName;


	uiComponentName="WINDOWS_UInterface";
	if(!CM.initUIComponent(uiComponentName))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the world model component
	if(!CM.initWorldModelComponent("STANDARD_WorldModel"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the scene manager
	if(!CM.initSceneManager("STANDARD_SceneManager"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	//initialise the projectile manager
	if(!CM.initProjectileManager("STANDARD_ProjectileManager"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

#ifdef _DEBUG 
#ifdef _WIN
	if(!CM.initProfiler("Profiler_WIN"))
	{
		system("pause");
		CM.close();
		exit(1);
	}
	if(!CM.PROFILER().init())
	{
		CM.LOGCONSOLE().Log()<<"LOG : ENGINE : Cannot get the processor frequency!\n";
	}
#endif

#ifdef _GP2X
	if(!CM.initProfiler("Profiler_GP2X"))
	{
		system("pause");
		CM.close();
		exit(1);
	}
#endif
#endif

	if(!CM.initExplosionManager("STANDARD_ExplosionManager"))
	{
		system("pause");
		CM.close();
		exit(1);
	}

	CM.initPhysicsEngine();
	CM.PHYSICS().m_gravity=(float)9.81;

	
}
void CEngine::load(void)
{

	//create the graph that represent the world
	//int depth = 2;
	//CM.SCENE().init(depth);
	//CM.WORLD().fillQuadTree();
	//CM.WORLD().scrollWorld(CVector2i(100, 100));

	//kinematic platform
	CShapeRectangle* rectangle1 = (CShapeRectangle*)CM.PHYSICS().createRectangle(500, 10);
	rectangle1->m_name = "Kinematic rectangle";
	rectangle1->m_bKinematic = true;
	rectangle1->m_position = CVector2f(0, 0);
	rectangle1->m_orientation = 0;

	//dynamic falling rectangle
	/*CShapeRectangle* fallingRectangle = (CShapeRectangle*)CM.PHYSICS().createRectangle(100, 50);
	fallingRectangle->m_bKinematic = false;
	fallingRectangle->m_name = "Falling Rectangle";
	fallingRectangle->m_mass=30;
	fallingRectangle->m_initialPosition = CVector2f(0, 250);
	fallingRectangle->m_initialSpeed = CVector2f(0, 0);
	fallingRectangle->m_initialOrientation = 0;*/

	//dynamic rectangle
	CShapeRectangle* rectangle2 = (CShapeRectangle*)CM.PHYSICS().createRectangle(50, 50);
	rectangle2->m_bKinematic = false;
	rectangle2->m_mass=30;
	rectangle2->m_initialPosition = CVector2f(-100, 250);
	rectangle2->m_initialSpeed = CVector2f(-15, -20);//-25
	rectangle2->m_initialOrientation = 0;//3.14/4;

	//dynamic circle
	CShapeCircle* circle1 = (CShapeCircle*)CM.PHYSICS().createCircle(20);
	circle1->m_bKinematic = false;
	circle1->m_initialPosition = CVector2f(260, 50);
	circle1->m_initialSpeed = CVector2f(0, -10);

	//projectile
	CShapeCircle* projectile = (CShapeCircle*)CM.PHYSICS().createCircle(40);
	projectile->m_name = "Projectile";
	projectile->m_bKinematic = false;
	projectile->m_initialPosition = CVector2f(-150, 150);
	projectile->m_initialSpeed = CVector2f(85, 0);

	//rectangle 3
	CShapeRectangle* rectangle3 = (CShapeRectangle*)CM.PHYSICS().createRectangle(120, 120);
	rectangle3->m_bKinematic = false;
	rectangle3->m_mass = 10;
	rectangle3->m_name = "Rectangle number 3";
	rectangle3->m_initialPosition = CVector2f(150, 300);
	rectangle3->m_initialSpeed = CVector2f(-45, 0);
	rectangle3->m_initialOrientation = (float)3.14/5;	
}

void CEngine::start(void)
{
	CM.LOGCONSOLE().Log()<<"LOG : ENGINE : Start Engine\n";

	const int tick=120;
	const int timeOfTick = 1000/tick;
	int currentTickTime=SDL_GetTicks();

	CM.SCENE().init(3);
	CM.PHYSICS().fillQuadTree();


	while(!CM.WORLD().quitGame())//while we don't want to quit the game
	{
		
		if(currentTickTime+timeOfTick<(int)SDL_GetTicks()) //tick
		{

			CM.UI().inputDoUpdate();

			//CM.WORLD().doUpdate();
			CM.PHYSICS().doUpdate();

			currentTickTime=SDL_GetTicks();
		}

#ifdef SHOWFPS
		m_fpsTicks=SDL_GetTicks()-m_lastTick;
		if(m_fpsTicks>1000)
		{
			m_fps=m_fpsCounter;
			m_lastTick=SDL_GetTicks();
			m_fpsCounter=0;
		}
		m_fpsCounter++;
		//char* buffer = new char[255];

		
		//string stringFPS("FPS : ");
		CM.LOGCONSOLE().Log()<<"LOG : FPS = "<<m_fps<<"\n";
		//stringFPS.append(buffer);
		//SetConsoleTitle(stringFPS.c_str());
#endif
		doRender();

	}


}

void CEngine::quit(void)
{
	CM.close();
}

void CEngine::doRender(void)
{
	CM.VISU().preRender();

	int radiusCircleCollisionPoint = 10;
	int lengthCollisionNormal = 50;

	Uint32 collisionPointColor = SDL_MapRGB(CM.VISU().getScreen()->format, 0, 255, 0);
	Uint32 collisionNormalColor = SDL_MapRGB(CM.VISU().getScreen()->format, 0, 0, 0);


	for(vector<IShape*>::iterator i = CM.PHYSICS().m_vectorOfPhysicEntities.begin(); i != CM.PHYSICS().m_vectorOfPhysicEntities.end(); i++)
	{
		eTypeShape type = (*i)->m_typeOfShape;
		CShapeRectangle* rectangle;
		CShapeCircle* circle;
		CVector2i screenPosition(0, 0);

		switch(type)
		{
		case eRectangleShape:
			rectangle = (CShapeRectangle*)(*i);

			//convert it into screen position
			screenPosition.m_x = (int)(rectangle->m_position.x + CM.VISU().getScreenWidth()/2);
			screenPosition.m_y = (int)(-rectangle->m_position.y + CM.VISU().getScreenHeight()/2);

			//draw a shape
			CM.VISU().displayRectangle(screenPosition, rectangle->m_width, rectangle->m_height, 
				SDL_MapRGB(CM.VISU().getScreen()->format, 0, 0, 255), -rectangle->m_orientation);

			//if collision, display the circle arround the collision point
			if(rectangle->m_collision)
			{
				for(vector<CCollisionInfo>::iterator i = rectangle->m_collisionInfo.begin(); i !=rectangle->m_collisionInfo.end(); i++)
				{
					//convert it into screen position
					screenPosition.m_x = (int)(i->m_collisionPoint.x + CM.VISU().getScreenWidth()/2);
					screenPosition.m_y = (int)(-i->m_collisionPoint.y + CM.VISU().getScreenHeight()/2);
					CM.VISU().displayCircle(screenPosition, radiusCircleCollisionPoint, collisionPointColor);

					//display the collision normal
					CVector2f firstPoint = i->m_collisionPoint + i->m_collisionNormal*(float)lengthCollisionNormal;
					CVector2f secondPoint = i->m_collisionPoint - i->m_collisionNormal*(float)lengthCollisionNormal;

					CVector2i screenFirstPoint;
					screenFirstPoint.m_x = (int)(firstPoint.x + CM.VISU().getScreenWidth()/2);
					screenFirstPoint.m_y = (int)(-firstPoint.y + CM.VISU().getScreenHeight()/2);

					CVector2i screenSecondPosition;
					screenSecondPosition.m_x = (int)(secondPoint.x + CM.VISU().getScreenWidth()/2);
					screenSecondPosition.m_y = (int)(-secondPoint.y + CM.VISU().getScreenHeight()/2);
					CM.VISU().displayLine(screenFirstPoint, screenSecondPosition, collisionNormalColor);
				}
			}

			break;

		case eCircleShape:
			circle = (CShapeCircle*)(*i);

			//convert it into screen position
			screenPosition.m_x = (int)(circle->m_position.x + CM.VISU().getScreenWidth()/2);
			screenPosition.m_y = (int)(-circle->m_position.y + CM.VISU().getScreenHeight()/2);

			//draw the shape
			CM.VISU().displayCircle(screenPosition, circle->m_radius,
				SDL_MapRGB(CM.VISU().getScreen()->format, 0, 0, 255));

			//if collision, display the circle arround the collision point
			if(circle->m_collision)
			{
				for(vector<CCollisionInfo>::iterator i = circle->m_collisionInfo.begin(); i !=circle->m_collisionInfo.end(); i++)
				{
					//display the circle arould the point
					//convert it into screen position
					screenPosition.m_x = (int)(i->m_collisionPoint.x + CM.VISU().getScreenWidth()/2);
					screenPosition.m_y = (int)(-i->m_collisionPoint.y + CM.VISU().getScreenHeight()/2);
					CM.VISU().displayCircle(screenPosition, radiusCircleCollisionPoint, collisionPointColor);

					//display the collision normal
					CVector2f firstPoint = i->m_collisionPoint + i->m_collisionNormal*(float)lengthCollisionNormal;
					CVector2f secondPoint = i->m_collisionPoint - i->m_collisionNormal*(float)lengthCollisionNormal;

					CVector2i screenFirstPoint;
					screenFirstPoint.m_x = (int)(firstPoint.x + CM.VISU().getScreenWidth()/2);
					screenFirstPoint.m_y = (int)(-firstPoint.y + CM.VISU().getScreenHeight()/2);

					CVector2i screenSecondPosition;
					screenSecondPosition.m_x = (int)(secondPoint.x + CM.VISU().getScreenWidth()/2);
					screenSecondPosition.m_y = (int)(-secondPoint.y + CM.VISU().getScreenHeight()/2);
					CM.VISU().displayLine(screenFirstPoint, screenSecondPosition, collisionNormalColor);

				}
			}
			break;
		
		}
	}

	CM.VISU().postRender();

	

}

